Skip to content

Update channel_reestablish for splicing #3886

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 13 commits into
base: main
Choose a base branch
from

Conversation

jkczyz
Copy link
Contributor

@jkczyz jkczyz commented Jun 24, 2025

The splicing spec extends the channel_reestablish message with two more TLVs indicating which funding txid the sender has sent/received either explicitly via splice_locked or implicitly via channel_ready. This allows peers to detect if a splice_locked was lost during disconnection and must be retransmitted.

To this end, the spec updates the channel_reestablish logic to support splicing.

@ldk-reviews-bot
Copy link

ldk-reviews-bot commented Jun 24, 2025

👋 Thanks for assigning @TheBlueMatt as a reviewer!
I'll wait for their review and will help manage the review process.
Once they submit their review, I'll check if a second reviewer would be helpful.

@ldk-reviews-bot
Copy link

🔔 1st Reminder

Hey @wpaulino! This PR has been waiting for your review.
Please take a look when you have a chance. If you're unable to review, please let us know so we can find another reviewer.

@jkczyz jkczyz assigned jkczyz and unassigned jkczyz Jun 26, 2025
@jkczyz jkczyz force-pushed the 2025-06-channel-reestablish branch 2 times, most recently from 06c0dfc to f000b76 Compare June 27, 2025 17:04
@jkczyz jkczyz marked this pull request as ready for review June 27, 2025 17:12
@jkczyz
Copy link
Contributor Author

jkczyz commented Jun 27, 2025

@wpaulino Ready for review now.

Copy link

codecov bot commented Jun 27, 2025

Codecov Report

Attention: Patch coverage is 60.67416% with 105 lines in your changes missing coverage. Please review.

Project coverage is 89.43%. Comparing base (82519a2) to head (b0291f4).
Report is 20 commits behind head on main.

Files with missing lines Patch % Lines
lightning/src/ln/channel.rs 45.31% 98 Missing and 7 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3886      +/-   ##
==========================================
+ Coverage   88.83%   89.43%   +0.59%     
==========================================
  Files         166      166              
  Lines      119259   125925    +6666     
  Branches   119259   125925    +6666     
==========================================
+ Hits       105943   112616    +6673     
+ Misses      10988    10944      -44     
- Partials     2328     2365      +37     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@ldk-reviews-bot
Copy link

🔔 2nd Reminder

Hey @wpaulino! This PR has been waiting for your review.
Please take a look when you have a chance. If you're unable to review, please let us know so we can find another reviewer.

@ldk-reviews-bot
Copy link

🔔 3rd Reminder

Hey @wpaulino! This PR has been waiting for your review.
Please take a look when you have a chance. If you're unable to review, please let us know so we can find another reviewer.

@ldk-reviews-bot
Copy link

🔔 4th Reminder

Hey @wpaulino! This PR has been waiting for your review.
Please take a look when you have a chance. If you're unable to review, please let us know so we can find another reviewer.

@jkczyz jkczyz self-assigned this Jul 3, 2025
@jkczyz jkczyz moved this to Goal: Merge in Weekly Goals Jul 3, 2025
@ldk-reviews-bot
Copy link

🔔 5th Reminder

Hey @wpaulino! This PR has been waiting for your review.
Please take a look when you have a chance. If you're unable to review, please let us know so we can find another reviewer.

@ldk-reviews-bot
Copy link

🔔 6th Reminder

Hey @wpaulino! This PR has been waiting for your review.
Please take a look when you have a chance. If you're unable to review, please let us know so we can find another reviewer.

@jkczyz jkczyz force-pushed the 2025-06-channel-reestablish branch from f000b76 to e2ea3bf Compare July 7, 2025 21:02
@jkczyz
Copy link
Contributor Author

jkczyz commented Jul 7, 2025

Rebased.

Copy link
Contributor

@wpaulino wpaulino left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We may need to double check our incoming channel_ready handling to make sure we can handle receiving one long after channel_ready was already exchanged due to the new logic surrounding your_last_funding_locked_txid.

@@ -10128,10 +10135,52 @@ where
}
}

#[cfg(splicing)]
fn maybe_get_your_last_funding_locked_txid(&self, features: &InitFeatures) -> Option<Txid> {
if !features.supports_splicing() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the TLVs are optional, I don't think we really need to check this and can always set them

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm.. if the implementation supports splicing but didn't set the feature bit, won't they understand the TLV?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. This method is only for an outgoing channel_reestablish so they'll just ignore the TLV if they don't support splicing.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I was overloading "supporting" here. What I meant was that the other implementation supported splicing in the sense they have code written. But for whatever reason they chose not to set the feature bit in their init message. In that sense, they might not ignore the TLV?

I guess in our implementation here we don't really do any checks around this but should always do the right thing (i.e., never send splice_locked) since in the above scenario as we'd never have any FundingScope where is_splice is true.

Though, it doesn't seem like we check their feature bits when handling any splice-related messages. Do we care if they tell us they don't support splicing but send us those messages anyway? At very least it seems we should check if they support splicing before attempting to initiate a splice.

&& !session.has_received_commitment_signed()
{
// FIXME
return unimplemented!();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI

@ldk-reviews-bot
Copy link

👋 The first review has been submitted!

Do you think this PR is ready for a second reviewer? If so, click here to assign a second reviewer.

@jkczyz jkczyz force-pushed the 2025-06-channel-reestablish branch from e2ea3bf to 69be701 Compare July 9, 2025 00:17
Copy link
Contributor Author

@jkczyz jkczyz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We may need to double check our incoming channel_ready handling to make sure we can handle receiving one long after channel_ready was already exchanged due to the new logic surrounding your_last_funding_locked_txid.

ACK. Also need to address https://github.com/lightningdevkit/rust-lightning/pull/3736/files#r2133028859.

@@ -10128,10 +10135,52 @@ where
}
}

#[cfg(splicing)]
fn maybe_get_your_last_funding_locked_txid(&self, features: &InitFeatures) -> Option<Txid> {
if !features.supports_splicing() {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm.. if the implementation supports splicing but didn't set the feature bit, won't they understand the TLV?

@jkczyz jkczyz force-pushed the 2025-06-channel-reestablish branch from 69be701 to f7b9785 Compare July 9, 2025 21:47
jkczyz added 4 commits July 9, 2025 16:49
While splicing is not yet fully supported, checking if the feature has
been negotiated is needed for changes to the channel_reestablish logic.
The splicing spec extends the channel_reestablish message with two more
TLVs indicating which funding txid the sender has sent/received either
explicitly via splice_locked or implicitly via channel_ready. This
allows peers to detect if a splice_locked was lost during disconnection
and must be retransmitted. This commit updates channel_reestablish with
the TLVs. Subsequent commits will implement the spec requirements.
The previous commit extended the channel_reestablish message with
your_last_funding_locked_txid and my_current_funding_locked_txid for use
as described there. This commit sets those fields to the funding txid
most recently sent/received accordingly.
When splicing is negotiated, channel_ready must be retransmitted when
your_last_funding_locked is not set. Further, the current logic for
retransmitting channel_ready is only applicable when splicing is not
negotiated.
jkczyz and others added 9 commits July 9, 2025 16:49
The ChannelState::NegotiatingFunding assertion check in
ChannelContext::get_initial_commitment_signed will fail when
implementing splicing's channel_reestablish logic. In order to support
it and channel establishment, enter ChannelState::FundingNegotiated
prior to calling the method and update the assertion accordingly.
When ChannelContext::get_initial_commitment_signed is called for V2
channel establishment, any errors should result in closing the channel.
However, in the future, when this is used for splicing it should abort
instead of closing the channel. Move the error construction to the call
sites in anticipation of this.
The splicing spec updates the logic pertaining to next_funding_txid when
handling a channel_reestablish message. Specifically:

A receiving node:
  - if `next_funding_txid` is set:
    - if `next_funding_txid` matches the latest interactive funding transaction
      or the current channel funding transaction:
      - if `next_commitment_number` is equal to the commitment number of the
        `commitment_signed` message it sent for this funding transaction:
        - MUST retransmit its `commitment_signed` for that funding transaction.
      - if it has already received `commitment_signed` and it should sign first,
        as specified in the [`tx_signatures` requirements](#the-tx_signatures-message):
        - MUST send its `tx_signatures` for that funding transaction.
      - if it has already received `tx_signatures` for that funding transaction:
        - MUST send its `tx_signatures` for that funding transaction.
    - if it also sets `next_funding_txid` in its own `channel_reestablish`, but the
      values don't match:
      - MUST send an `error` and fail the channel.
    - otherwise:
      - MUST send `tx_abort` to let the sending node know that they can forget
        this funding transaction.

This commit updates FundedChannel::channel_reestablish accordingly.

Co-authored-by: Wilmer Paulino <[email protected]>
Co-authored-by: Jeffrey Czyz <[email protected]>
The splicing spec updates the logic pertaining to next_commitment_number
when sending a channel_reestablish message. Specifically:

The sending node:
  - if it has sent `commitment_signed` for an interactive transaction construction but
    it has not received `tx_signatures`:
    - MUST set `next_funding_txid` to the txid of that interactive transaction.
    - if it has not received `commitment_signed` for that interactive transaction:
      - MUST set `next_commitment_number` to the commitment number of the `commitment_signed` it sent.
The channel_reestablish protocol supports retransmitting splice_locked
messages as needed. Add support for doing such when handling
channel_reestablish messages.
The splicing spec updates channel_establishment logic to retransmit
channel_ready or splice_locked for announced channels. Specifically:

- if `my_current_funding_locked` is included:
  - if `announce_channel` is set for this channel:
    - if it has not received `announcement_signatures` for that transaction:
      - MUST retransmit `channel_ready` or `splice_locked` after exchanging `channel_reestablish`.
When a splice transaction is promoted (i.e., when splice_locked has been
exchanged), announcement_signatures must be sent. However, if we try to
send a channel_announcement before they are received, then the
signatures will be incorrect. To avoid this, clear the counterparty's
announcement_signatures upon promoting a FundingScope.
The channel_reestablish protocol supports retransmitting channel_ready
messages as needed. Add support for doing such when handling
channel_reestablish messages.
When handling a counterparties channel_reestablish, the spec dictates
that a splice_locked may be implied by my_current_funding_locked.
Compare that against any pending splices and handle an implicit
splice_locked message when applicable.
@jkczyz jkczyz force-pushed the 2025-06-channel-reestablish branch from f7b9785 to b0291f4 Compare July 9, 2025 21:49
@jkczyz
Copy link
Contributor Author

jkczyz commented Jul 9, 2025

Also need to address https://github.com/lightningdevkit/rust-lightning/pull/3736/files#r2133028859.

Latest push adds some commits to address this.

@jkczyz jkczyz requested a review from TheBlueMatt July 9, 2025 22:20
@jkczyz
Copy link
Contributor Author

jkczyz commented Jul 9, 2025

We may need to double check our incoming channel_ready handling to make sure we can handle receiving one long after channel_ready was already exchanged due to the new logic surrounding your_last_funding_locked_txid.

Looks like we have some logic below. I think the catch-all case still holds? We should only receive a channel_ready if we didn't set your_last_funding_locked_txid.

// If we reconnected before sending our `channel_ready` they may still resend theirs.
ChannelState::ChannelReady(_) => check_reconnection = true,
_ => return Err(ChannelError::close("Peer sent a channel_ready at a strange time".to_owned())),
}
if check_reconnection {
// They probably disconnected/reconnected and re-sent the channel_ready, which is
// required, or they're sending a fresh SCID alias.
let expected_point =
if self.context.cur_counterparty_commitment_transaction_number == INITIAL_COMMITMENT_NUMBER - 1 {
// If they haven't ever sent an updated point, the point they send should match
// the current one.
self.context.counterparty_cur_commitment_point
} else if self.context.cur_counterparty_commitment_transaction_number == INITIAL_COMMITMENT_NUMBER - 2 {
// If we've advanced the commitment number once, the second commitment point is
// at `counterparty_prev_commitment_point`, which is not yet revoked.
debug_assert!(self.context.counterparty_prev_commitment_point.is_some());
self.context.counterparty_prev_commitment_point
} else {
// If they have sent updated points, channel_ready is always supposed to match
// their "first" point, which we re-derive here.
Some(PublicKey::from_secret_key(&self.context.secp_ctx, &SecretKey::from_slice(
&self.context.commitment_secrets.get_secret(INITIAL_COMMITMENT_NUMBER - 1).expect("We should have all prev secrets available")
).expect("We already advanced, so previous secret keys should have been validated already")))
};
if expected_point != Some(msg.next_per_commitment_point) {
return Err(ChannelError::close("Peer sent a reconnect channel_ready with a different point".to_owned()));
}
return Ok(None);
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: Goal: Merge
Development

Successfully merging this pull request may close these issues.

3 participants